﻿using System.Collections;
using System.Collections.Generic;
using ClassLibrary;
using ClassLibrary.Communication;
using ClassLibrary.SignalType;
using System;
using ClassLibrary.SignalType.SynchronousTransportModuleLevel1.VirtualContainer;

namespace NetworkNode.Switching
{
    /// <summary>
    /// @Author Marcin Król
    /// </summary>
    class Multiplexer
    {
        private readonly bool _isDummy;

        private readonly int _multiplexerId;

        private readonly int _egressLogicalPortId;
        private readonly int _firstIngressPhysicalPortId;

        //[portId,Port]
        private readonly Dictionary<int,Port> _portsDictionary = new Dictionary<int, Port>();
        //[portId, Adapter]
        private readonly Dictionary<int, Adapter> _adaptersDictionary = new Dictionary<int, Adapter>();

        public Multiplexer(IEnumerable<Port> ports, int multiplexerId, int egressLogicalPortId, int firstIngressPhysicalPortId)
        {
            _multiplexerId = multiplexerId;
            _egressLogicalPortId = egressLogicalPortId;
            _firstIngressPhysicalPortId = firstIngressPhysicalPortId;
            foreach (var port in ports)
            {
                port.DataReceived += HandleDataReceivedEvent;
                _portsDictionary[port.Id] = port;
                _adaptersDictionary[port.Id] = new Adapter(VCType.VC12);//TODO
                _isDummy = false;
            }
        }

        public int MultiplexerId
        {
            get { return _multiplexerId; }
        }

        public int EgressLogicalPortId
        {
            get { return _egressLogicalPortId; }
        }

        void HandleDataReceivedEvent(Object sender, EventType eventType)
        {
            switch (eventType)
            {
                case EventType.DataReceived:
                    OnDataPackageReceived((DataPackage)((Port)sender).Read(), ((Port)sender).Id);
                    break;
            }
        }

        void OnDataPackageReceived(DataPackage dataPackage, int ingressPortId)
        {
            if (Utils.Test)
            {
                Console.WriteLine("%DataPackage Received<========================");
                Console.WriteLine(dataPackage.ToString());
            }
            var adapter = _adaptersDictionary[ingressPortId];
            adapter.ObtainDataPackage(dataPackage);
        }

        public Vc4 Demultiplex()
        {
            Vc4 vc4 = null;
            if (_isDummy)
            {
                //Multiplexer is dummy which means that there is only one client
                //connected to it, hence adapted virtualcontainer is
                //vc4 and should go through without modification

                //get the only adapter
                var adapterEnumerator = _adaptersDictionary.GetEnumerator();
                adapterEnumerator.MoveNext();
                var adapter = adapterEnumerator.Current.Value;

                var virtualContainer = adapter.AdaptObtainedData();
                if (virtualContainer != null)
                {
                    vc4 = (Vc4)virtualContainer;
                }
            }
            else
            {
                //there is more than one client connected to the multiplexer

                foreach (var adaptersDictionaryRecord in _adaptersDictionary)
                {
                    var adapter = adaptersDictionaryRecord.Value;
                    var ingressPortId = adaptersDictionaryRecord.Key;
                    var vcId = ingressPortId - _firstIngressPhysicalPortId;

                    var virtualContainer = adapter.AdaptObtainedData();
                    if (virtualContainer != null)
                    {
                        if (vc4 == null)
                        {
                            vc4 = new Vc4(){Poh = Utils.GeneratePoh()};
                        }
                        vc4.SetVirtualContainer((Vc)virtualContainer, vcId);
                    }
                    
                }
            }
            
            return vc4;
        }

        public void MultiplexAndSend(Vc4 vc4)
        {
            if (_isDummy)
            {
                const int vcId = 0;
                var portId = _firstIngressPhysicalPortId + vcId;
                _portsDictionary[portId].Send(Adapter.Release(vc4));
            }
            else
            {
                var vcs = vc4.Vcs;
                foreach (int vcId in vcs.Keys)
                {
                    var vc = vcs[vcId];
                    var portId = _firstIngressPhysicalPortId + vcId;
                    _portsDictionary[portId].Send(Adapter.Release(vc));
                }
            }
        }

        

        
    }
}
